package com.framework.spring.web;

import com.alibaba.fastjson.JSONObject;
import com.framework.spring.annotations.Component;
import com.framework.spring.annotations.Controller;
import com.framework.spring.annotations.Param;
import com.framework.spring.annotations.RequestMapping;
import com.framework.spring.postprocessors.BeanPostProcessor;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

@Component
public class DispatcherServlet extends HttpServlet implements BeanPostProcessor {

    Map<String, RequestHandler> handlerMap = new HashMap<>();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String uri = req.getRequestURI();
        RequestHandler handler;
        if ((handler = handlerMap.get(uri)) == null) {
            resp.setContentType("text/html;charset=UTF-8");
            resp.getWriter().write("<h1> 你的请求路径有误，请检查<h1>");
            return;
        }
        try {
            Object[] args = resolveArgs(req, handler.getMethod());
            Object result = handler.handle(args);
            switch (handler.getType()) {
                case JSON:
                    resp.setContentType("application/json;charset=UTF-8");
                    resp.getWriter().write(JSONObject.toJSONString(result));
                    break;
                case HTML:
                    resp.setContentType("text/html;charset=UTF-8");
                    resp.getWriter().write(result.toString());
                    break;
            }
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }

    private Object[] resolveArgs(HttpServletRequest req, Method method) {
        Parameter[] parameters = method.getParameters();
        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            String paramStr = req.getParameter(parameter.getAnnotation(Param.class).value());
            if (String.class.isAssignableFrom(parameter.getType())) {
                args[i] = paramStr;
            } else if (Integer.class.isAssignableFrom(parameter.getType())) {
                args[i] = Integer.parseInt(paramStr);
            }
        }
        return args;
    }

    @Override
    public Object afterInitialization(Object bean, String name) {
        Class<?> beanClass = bean.getClass();
        if (beanClass.isAnnotationPresent(Controller.class)) {
            String prefix = beanClass.isAnnotationPresent(RequestMapping.class) ? beanClass.getAnnotation(RequestMapping.class).value() : "";
            for (Method method : beanClass.getDeclaredMethods()) {
                if (method.isAnnotationPresent(RequestMapping.class)) {
                    String key = prefix + method.getAnnotation(RequestMapping.class).value();
                    if (handlerMap.put(key, wrapHandler(bean, method)) != null) {
                        throw new RuntimeException("请求路径重复定义：" + key);
                    }
                }
            }
        }
        return bean;
    }

    private RequestHandler wrapHandler(Object bean, Method method) {
        return new RequestHandler(method, bean);

    }
}
